﻿using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;

namespace JsValidator.Tests
{
    [TestFixture]
    public class IntegrationTests
    {
        private FakeReporter _reporter;
        private string _configFilePath;

        [Test]
        public void CheckJavaInstalledOnCurrentPC()
        {
            try
            {
                var process = new Process { StartInfo = new ProcessStartInfo("java.exe") };
                process.Start();
            }
            catch (Exception)
            {
                throw new InvalidOperationException("No Java installed on current PC (or Java not added to PATH)");
            }
        }


        [SetUp]
        public void Setup()
        {
            _reporter = new FakeReporter();
        }

        private const string DefaultConfig = "";

        [Test]
        public void NoJavaInstalled_ErrorReported()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/SimpleCorrect.js""
                          ]
                        }";

            var processor = CreateProcessor(json);
            processor.JavaPath = "asd";
            processor.Process();

            _reporter.Errors.Any(x => x.Contains("Java not installed")).Should().BeTrue();
            _reporter.Warnings.Count().Should().Be(0);
        }

        [Test]
        public void NoJavaInstalled_WarningReported()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/SimpleCorrect.js""
                          ],
                           ""TreatNoJavaAsWarning"" : true
                        }";

            var processor = CreateProcessor(json);
            processor.JavaPath = "asd";
            processor.Process();

            _reporter.Errors.Count().Should().Be(0);
            _reporter.Warnings.Any(x => x.Contains("Java not installed")).Should().BeTrue();
        }

        [Test]
        public void EverythingsCorrect_NoErrors_NoWarnings()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/SimpleCorrect.js""
                          ]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(0);
            _reporter.Warnings.Count().Should().Be(0);
        }

        [Test]
        public void SimpleIncorrect_ErrorReported()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/SimpleIncorrect.js""
                          ]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(1);
            _reporter.Warnings.Count().Should().Be(0);
        }

        [Test]
        public void SimpleIncorrect2_OneErrorHidden()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/SimpleIncorrect2.js""
                          ],
                          ""IgnoreErrors"" : [
                                ""variable qwe is undefined""
                          ]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(1);
            _reporter.Errors.First().Should().Contain("variable zxc is undefined");
            _reporter.Warnings.Count().Should().Be(0);
        }

        [Test]
        public void ComplexIncorrect_WarningReported()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/ComplexInCorrect.js""
                          ]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(0);
            _reporter.Warnings.Count().Should().Be(2);
        }

        [Test]
        public void ComplexIncorrect_ErrorReported()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/ComplexInCorrect.js""
                          ],
                           ""Warnings"": [""never defined""]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(2);
            _reporter.Warnings.Count().Should().Be(0);
        }

        [Test]
        public void ComplexIncorrect2_ErrorReported()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/ComplexInCorrect2.js""
                          ],
                           ""Warnings"": [""never defined""]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(1);
            _reporter.Warnings.Count().Should().Be(1);
        }

        [Test]
        public void ExternalLibraryUsage_NotFound()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/jQueryUsage.js""
                          ],
                            ""externs"": [ ""//jquery-1.743.js"" ]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(1);
        }

        [Test]
        public void JQueryUsage_Warning()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/jQueryUsage.js""
                          ],
                            ""externs"": [ ""//jquery-1.7.js"" ]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(0);
            _reporter.Warnings.Count().Should().Be(1);
        }

        [Test]
        public void JQueryUsage_JqueryStoredLocally_NoError()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/jQueryUsage.js""
                          ],
                            ""externs"": [ ""TestFiles\\extern\\jquery-1.7.js"" ],
                            ""IgnoreAllWarnings"": true
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(0);
            _reporter.Warnings.Count().Should().Be(0);
        }

        [Test]
        public void JQueryUsage_IgnoreWarnings_NoError()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles/jQueryUsage.js""
                          ],
                            ""externs"": [ ""TestFiles\\extern\\jquery-1.7.js"" ],
                            ""IgnoreWarnings"": [""Constructor function .* should be called""]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(0);
            _reporter.Warnings.Count().Should().Be(0);
        }

        [Test]
        public void Extern_RelativePath()
        {
            var json = @"{
                          ""inputs"": [
                            ""../TestFiles/jQueryUsage.js""
                          ],
                            ""externs"": [ ""..\\TestFiles\\extern\\jquery-1.7.js"" ],
                            ""IgnoreWarnings"": [""Constructor function .* should be called""]
                        }";

            CreateProcessor(json);
            new Processor(_reporter, _configFilePath, "FakeDir").Process();

            _reporter.Errors.Count().Should().Be(0);
            _reporter.Warnings.Count().Should().Be(0);
        }


        [Test]
        public void EmptyInput()
        {
            var json = @"{
                          ""inputs"": []
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(1);
            _reporter.Warnings.Count().Should().Be(0);
            _reporter.Errors.First().Should().Contain("no js files specified to process");
        }

        [Test]
        public void ConfigBroken_ErrorReported()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles\ComplexInCorrect.js""
                          ]
                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(1);
            _reporter.Errors.Should().Contain(x => x.Contains("Error parsing config"));
            _reporter.Warnings.Count().Should().Be(0);
        }

        [Test]
        public void SuppressThis_IgnoreCase()
        {
            var json = @"{
                          ""inputs"": [
                            ""TestFiles\\SuppressThis.js""
                          ],
                            ""Warnings"": [""parse error""]

                        }";

            CreateProcessor(json).Process();

            _reporter.Errors.Count().Should().Be(1);
            _reporter.Warnings.Count().Should().Be(0);
            _reporter.Errors.Should().Contain(x => x.Contains("Parse"));
        }

        private Processor CreateProcessor(string configText)
        {
            _configFilePath = Path.GetTempFileName();

            File.WriteAllText(_configFilePath, configText);
            return new Processor(_reporter, _configFilePath, "");
        }

        [TearDown]
        public void TearDown()
        {
            if (!String.IsNullOrEmpty(_configFilePath))
                File.Delete(_configFilePath);
        }
    }
}